package com.blue.crawler.engine;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

import com.blue.crawler.model.FileModel;
import com.blue.crawler.model.ListDetailModel;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.blue.core.util.UrlUtil;
import com.blue.crawler.annotation.CrawlerConfig;
import com.blue.crawler.annotation.CrawlerPathConfig;
import com.blue.crawler.annotation.Parser;
import com.blue.crawler.util.CrawlerInvoker;
import com.blue.crawler.util.HttpException;


public class TestListDetailEngine<T extends ListDetailModel>
{
	private static Logger logger = LoggerFactory.getLogger(TestListDetailEngine.class);
	
	private final CrawlerInvoker invoker;
	private final Parser parser;
	private final CrawlerConfig config;
	private final CrawlerPathConfig pathConfig;
	private final ListDetailCrawl<T> crawl;

	@SuppressWarnings("unchecked")
	public TestListDetailEngine(Class<T> clazz) throws Exception
	{
		this.invoker = new CrawlerInvoker();
		this.parser = Parser.getInstance();
		this.config = parser.parse(clazz);
		logger.info("CrawlerPathConfig 个数：{}", config.getPathList());
		this.pathConfig = config.getPathList() != null && !config.getPathList().isEmpty() ? config.getPathList().get(0) : null;
		this.crawl = (ListDetailCrawl<T>)config.getCrawler().newInstance();
	}

	
	public final void handleList(String url, boolean all) throws Exception
	{
		String html = this.invoke(url);
		List<T> list = crawl.queryList(html, config, pathConfig);
		if (list == null || list.isEmpty())
		{
			logger.warn("列表个数：空");
			return;
		}

		logger.info("列表个数：{}", list.size());
		for (T doc : list)
		{
			System.out.printf("title: %s\nurl: %s\ncover: %s\ncreateTime: %s\nsummary: %s\n", doc.getTitle(), doc.getUrl(), doc.getCover(), doc.getCreateTime(), doc.getSummary());
			System.out.println("====================");
		}
		
		if (all)
		{
			T obj = list.get(0);
			logger.info("解析：{}", obj.getUrl());
			this.handleOne(obj);
		}
	}
	
	public void handleOne(T obj, String url) throws IOException
	{
		Assert.notNull(obj, "对象不能为空");
		obj.setUrl(url);
		this.handleOne(obj);
	}

	private void handleOne(T obj) throws IOException
	{
		String url = UrlUtil.getLink(pathConfig.getUrl(), obj.getUrl());
		
		Queue<String> pageQueue = new LinkedList<>();
		pageQueue.offer(url);
		Set<String> pageSet = new HashSet<>();
		pageSet.add(url);
		List<String> pageContent = new ArrayList<>();
		
		Set<String> urlSet = new LinkedHashSet<>(); // 附件URL
		
		int i = 1;
		while ((url = pageQueue.poll()) != null)
		{
			logger.info("解析：{}", url);
			this.sleep();
			String html = this.invoke(url);
			List<String> urlList = crawl.query(html, config, pathConfig, obj);
			if (urlList != null && !urlList.isEmpty())
				urlSet.addAll(urlList);
			
			if (obj.getContent() != null && !pageContent.contains(obj.getContent()))
				pageContent.add(obj.getContent());
			
			List<String> pList = crawl.queryPage(html, config, pathConfig, obj, i);
			if (pList != null)
			{
				for (String p : pList)
				{
					p = UrlUtil.getLink(url, p);
					if (!pageSet.contains(p))
					{
						pageSet.add(p);
						pageQueue.offer(p);
					}
				}
			}
			i++;
			
		}
		String content = StringUtils.join(pageContent, "\n<!-- break_page -->\n");
		
		List<FileModel> picModelList = new ArrayList<>();
		for (String picUrl : urlSet)
		{
			picUrl = UrlUtil.getLink(url, picUrl);
			FileModel model = new FileModel();
			picModelList.add(model);
			model.setPath(picUrl);
		}
		
		obj.setContent(content);
		obj.setFileList(picModelList);
		
		System.out.println("======详细=======");
		System.out.printf("title: %s\ncover: %s\ncreateTime: %s\nsummary: %s\ncontent: %s\n", obj.getTitle(), obj.getCover(), obj.getCreateTime(), obj.getSummary(), obj.getContent());
		if (obj.getFileList() != null && !obj.getFileList().isEmpty())
		{
			System.out.println("picList: ");
			for (FileModel model : obj.getFileList())
			{
				System.out.println(model.getPath());
			}
		}
	}
	
	/**
	 * 暂停爬虫
	 */
	private void sleep()
	{
		if (config.getInterval() <= 0)
			return;
		
		try
		{
			Thread.sleep(config.getInterval() * 1000);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}
	
	/**
	 * 调用HTTP请求
	 * 
	 * @param url URL地址
	 * @return HTML文本
	 */
	private String invoke(String url) throws IOException, HttpException
	{
		Proxy proxy = null;
		if (config.isProxy())
		{
			InetSocketAddress addr = new InetSocketAddress(config.getProxyHost(), config.getProxyPort());
			proxy = new Proxy(config.getProxyType(), addr);
		}
		return invoker.get(url, proxy, pathConfig.getHeaders());
	}
	
	
}
